
/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: implementation of dtoe driver for hi1822 chip
 * Create: 2023-10-19
 * Author: Huawei
 */
#ifdef _PCLINT_
#include "toe_pclint.h"
#else
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pm.h>
#include "hinic3_hw.h"
#include "hinic3_lld.h"
#endif

#include "hisec_hwrand.h"
#include "hisec_crypt_dev.h"

static struct crypt_device *crypt_cryptdev_alloc(struct hinic3_lld_dev *lld_dev)
{
    struct crypt_device *crypt_dev = NULL;
    crypt_dev = (struct crypt_device *)kzalloc(sizeof(struct crypt_device), GFP_KERNEL);
    crypt_dev->lld_dev = lld_dev;
    crypt_dev->hwdev = lld_dev->hwdev;
    crypt_dev->pdev = lld_dev->pdev;

    return crypt_dev;
}

static void crypt_cryptdev_free(struct crypt_device *crypt_dev)
{
    if (crypt_dev != NULL) {
        kfree(crypt_dev);
        crypt_dev = NULL;
    }
}

static int crypt_cryptserv_init(struct crypt_device *crypt_dev)
{
    int ret = 0;
    if (hinic3_func_type(crypt_dev->hwdev) == TYPE_PPF) {
        ret = hisec_trng_init(crypt_dev->hwdev);
    }
    if (ret != 0) {
        pr_err("Init trng failed, ret = %d\n", ret);
        return ret;
    }
    return 0;
}

static void crypt_cryptserv_deinit(struct crypt_device *crypt_dev)
{
    if (hinic3_func_type(crypt_dev->hwdev) == TYPE_PPF) {
        hisec_trng_deinit();
    }
}

static int crypt_probe(struct hinic3_lld_dev *lld_dev, void **uld_dev, char *uld_dev_name)
{
    struct crypt_device *crypt_dev = NULL;
    int ret = 0;
    crypt_dev = crypt_cryptdev_alloc(lld_dev);
    if (crypt_dev == NULL) {
        pr_err("Alloc cryptdev failed, crypt_dev = NULL\n");
        goto err_dev_alloc;
    }
    *uld_dev = (void *)crypt_dev;
    ret = crypt_cryptserv_init(crypt_dev);
    if (ret != 0) {
        pr_err("Init cryptserv failed, ret = %d\n", ret);
        goto err_serv_init;
    }
    return 0;

err_serv_init:
    crypt_cryptdev_free(crypt_dev);
err_dev_alloc:
    return -EINVAL;
}

static void crypt_remove(struct hinic3_lld_dev *lld_dev, void *uld_dev)
{
    struct crypt_device *crypt_dev = NULL;
    crypt_dev = (struct crypt_device *)uld_dev;
    crypt_cryptserv_deinit(crypt_dev);
    crypt_cryptdev_free(crypt_dev);
}

struct hinic3_uld_info g_crypt_uld_info = {
    .probe = crypt_probe,
    .remove = crypt_remove,
    .suspend = NULL,
    .resume = NULL,
    .event = NULL,
    .ioctl = NULL,
};

static int __init crypt_init(void)
{
    int ret = 0;
    ret = hinic3_register_uld(SERVICE_T_CRYPT, &g_crypt_uld_info);
    if (ret) {
        pr_err("Register crypt hinic3 uld failed, ret = %d\n", ret);
        return ret;
    }

    return 0;
}

static void __exit crypt_exit(void)
{
    hinic3_unregister_uld(SERVICE_T_CRYPT);
}

module_init(crypt_init);
module_exit(crypt_exit);

MODULE_AUTHOR(HICRYPT_DRV_AUTHOR);
MODULE_DESCRIPTION(HICRYPT_DRV_DESC);
MODULE_VERSION(HICRYPT_DRV_VERSION);
MODULE_LICENSE("GPL");